package Singleton;
//单例模式基本实现

/**
 * 首先单例类必须要有一个 private 访问级别的构造函数，只有这样，才能确保单例不会在系统中的其他代码内被实例化，；
 * 其次，instance 成员变量和 getInstance 方法必须是 static 的。
 * 上述代码唯一的不足是无法对 instance 实例做延时加载，例如单例的创建过程很慢，
 * 而由于 instance 成员变量是 static 定义的，因此在 JVM 加载单例类时，单例对象就会被建立，
 * 如果此时这个单例类在系统中还扮演其他角色，
 * 那么在任何使用这个单例类的地方都会初始化这个单例变量，而不管是否会被用到。
 */
public class SingletonBase implements Runnable {
    //私有化的构造函数
    private SingletonBase(){
        System.out.println("Singleton is create");
    }
//    private static SingletonBase instance = new SingletonBase();//创建单例,无法延时加载
//    public static SingletonBase getInstance(){
//        return instance;
//    }

    /**
     * 延时加载方法
     */
    /**
     * 单例模式使用内部类来维护单例的实例，当 StaticSingleton 被加载时，其内部类并不会被初始化，
     * 故可以确保当 StaticSingleton 类被载入 JVM 时，不会初始化单例类，而当 getInstance() 方法调用时，
     * 才会加载 SingletonHolder，从而初始化 instance。同时，由于实例的建立是时在类加载时完成，
     * 故天生对多线程友好，getInstance() 方法也无需使用同步关键字。
     */
    private static class SingletonHandler{
        private static SingletonBase instance = new SingletonBase();
    }
    public static SingletonBase getInstance(){
        return SingletonHandler.instance;
    }
    public static void createSingleton(){
        System.out.println("create singleton");
    }
    public static void main(String[] args) {
//        SingletonBase s1 = SingletonBase.getInstance();
//        SingletonBase s2 = SingletonBase.getInstance();
//        System.out.println("s1 = s2?:"+(s1==s2));
//        SingletonBase.createSingleton();
        for (int i = 0; i < 5; i++) {
            new Thread(new SingletonBase()).start();
        }
    }

    @Override
    public void run() {
        long beginTime = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            SingletonBase.getInstance();
        }
        System.out.println(System.currentTimeMillis()-beginTime);
    }
}
